Table of Contents

  • 1  Preamble
    • 1.1  Imports
    • 1.2  Lists
    • 1.3  Formatting functions
    • 1.4  API call functions
  • 2  Data aquisition
    • 2.1  Fetch online data
    • 2.2  Format data
    • 2.3  Save data
  • 3  Check changes
    • 3.1  Load latest file
    • 3.2  Generate changelog
  • 4  Data visualisation
    • 4.1  Full data
    • 4.2  Card types
    • 4.3  Monsters
      • 4.3.1  Attributes
      • 4.3.2  Primary types
        • 4.3.2.1  Has effect discrimination
        • 4.3.2.2  Is pendulum discrimination
        • 4.3.2.3  By attribute
      • 4.3.3  Secondary types
        • 4.3.3.1  By attribute
        • 4.3.3.2  By secondary type
      • 4.3.4  Monster types
        • 4.3.4.1  By Attribute
        • 4.3.4.2  By primary type
        • 4.3.4.3  By secondary type
      • 4.3.5  Effect type
      • 4.3.6  ATK
      • 4.3.7  DEF
      • 4.3.8  Level/Rank
        • 4.3.8.1  ATK statistics
        • 4.3.8.2  DEF statistics
      • 4.3.9  Pendulum scale
        • 4.3.9.1  ATK statistics
        • 4.3.9.2  DEF statistics
        • 4.3.9.3  Level/Rank statistics
      • 4.3.10  Link
        • 4.3.10.1  ATK statistics
      • 4.3.11  Link Arrows
        • 4.3.11.1  By combination
        • 4.3.11.2  By unique
        • 4.3.11.3  By link
    • 4.4  Spell & Trap
      • 4.4.1  Properties
      • 4.4.2  Effect type
        • 4.4.2.1  Spell & Trap discrimination
    • 4.5  Archseries
      • 4.5.1  By card type
      • 4.5.2  By primary type
      • 4.5.3  By secondary type
      • 4.5.4  By monster type
      • 4.5.5  By property
    • 4.6  Artworks
      • 4.6.1  By card type
      • 4.6.2  By primary type
    • 4.7  Errata
      • 4.7.1  By card type
      • 4.7.2  By primary type
      • 4.7.3  By artwork
    • 4.8  TCG & OCG status
      • 4.8.1  TGC status
        • 4.8.1.1  By card type
        • 4.8.1.2  By monster type
        • 4.8.1.3  By archseries
      • 4.8.2  OCG status
        • 4.8.2.1  By card type
        • 4.8.2.2  By monster type
        • 4.8.2.3  By archseries
      • 4.8.3  TCG vs. OCG status
  • 5  HTML export
  • 6  Searches

Preamble¶

Imports¶

import glob
import os
import pandas as pd
import numpy as np
import seaborn as sns
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm, Normalize
from matplotlib_venn import venn2
from datetime import datetime
from ast import literal_eval

Lists¶

# Attributes to split monsters query
attributes = ['DIVINE', 'LIGHT', 'DARK', 'WATER', 'EARTH', 'FIRE', 'WIND']

# API variables
api_url = 'https://yugipedia.com/api.php'

# Styling dictionaries
arrows_dict = {'Middle-Left': '\u2190', 'Middle-Right': '\u2192', 'Top-Left': '\u2196', 'Top-Center': '\u2191', 'Top-Right': '\u2197', 'Bottom-Left': '\u2199', 'Bottom-Center': '\u2193', 'Bottom-Right': '\u2198'}
card_colors = {'Effect Monster': '#FF8B53', 'Normal Monster': '#FDE68A', 'Ritual Monster': '#9DB5CC', 'Fusion Monster': '#A086B7', 'Synchro Monster': '#CCCCCC', 'Xyz Monster': '#000000', 'Link Monster': '#00008B', 'Pendulum Monster': 'r', 'Monster Card': '#FF8B53', 'Spell Card': '#1D9E74', 'Trap Card': '#BC5A84', 'Monster Token': '#C0C0C0', 'FIRE': '#fd1b1b', 'WATER': '#03a9e6', 'EARTH': '#060d0a', 'WIND': '#77bb58', 'DARK': '#745ea5', 'LIGHT': '#9d8047', 'DIVINE': '#7e6537', 'Level': '#f1a41f'}

Formatting functions¶

def extract_results(df):
    df = pd.DataFrame(df['query']['results']).transpose()
    df = pd.DataFrame(df['printouts'].values.tolist())
    return df

def extract_artwork(row):
    result = tuple()
    if 'Category:OCG/TCG cards with alternate artworks' in row:
        result += ('Alternate',)
    if 'Category:OCG/TCG cards with edited artworks' in row:
        result += ('Edited',)
    if result == tuple():
        return np.nan
    else:
        return result

def concat_errata(row):
    result = tuple()
    if row['Name errata']:
        result += ('Name',)
    if row['Type errata']:
        result += ('Type',)
    if result == tuple():
        return np.nan
    else:
        return result 
    
def format_df(input_df, input_errata_df):
    df = pd.DataFrame()
    if 'Name' in input_df.columns:
        df['Name'] = input_df['Name'].dropna().apply(lambda x: x[0])
    if 'Password' in input_df.columns:
        df['Password'] = input_df['Password'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Card type' in input_df.columns:
        df['Card type'] = input_df['Card type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Property' in input_df.columns:
        df['Property'] = input_df['Property'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Primary type' in input_df.columns:
        df['Primary type'] = input_df['Primary type'].dropna().apply(lambda x: [i['fulltext'] for i in x] if len(x)>0 else []).apply(lambda y: list(filter(lambda z: z != 'Pendulum Monster', y)) if len(y)>0 else []).apply(lambda y: list(filter(lambda z: z != 'Effect Monster', y))[0] if len(y)>1 else (y[0] if len(y)>0 else np.nan))
    if 'Secondary type' in input_df.columns:
        df['Secondary type'] = input_df['Secondary type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Attribute' in input_df.columns:
        df['Attribute'] = input_df['Attribute'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Monster type' in input_df.columns:
        df['Monster type'] = input_df['Monster type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Level/Rank' in input_df.columns:
        df['Level/Rank'] = input_df['Level/Rank'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'ATK' in input_df.columns:
        df['ATK'] = input_df['ATK'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'DEF' in input_df.columns:
        df['DEF'] = input_df['DEF'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Pendulum Scale' in input_df.columns:
        df['Pendulum Scale'] = input_df['Pendulum Scale'].dropna().apply(lambda x: str(x[0]) if len(x)>0 else np.nan)
    if 'Link' in input_df.columns:
        df['Link'] = input_df['Link'].dropna().apply(lambda x: str(x[0]) if len(x)>0 else np.nan)
    if 'Link Arrows' in input_df.columns:
        df['Link Arrows'] = input_df['Link Arrows'].dropna().apply(lambda x: tuple([arrows_dict[i] for i in sorted(x)]) if len(x)>0 else np.nan)
    if 'Effect type' in input_df.columns:
        df['Effect type'] = input_df['Effect type'].dropna().apply(lambda x: tuple(sorted([i['fulltext'] for i in x])) if len(x)>0 else np.nan)
    if 'Archseries' in input_df.columns:
        df['Archseries'] = input_df['Archseries'].dropna().apply(lambda x: tuple(sorted(x)) if len(x)>0 else np.nan)
    if 'Category' in input_df.columns:
        df['Artwork'] = input_df['Category'].dropna().apply(lambda x: [i['fulltext'] for i in x] if len(x)>0 else np.nan).apply(extract_artwork)
    # Erratas column
    if input_errata_df is not None and 'Page name' in input_df.columns:
        df['Errata'] = errata_df.merge(input_df['Page name'].dropna().apply(lambda x: x[0]).rename('Name'), right_on = 'Name', left_index = True).apply(concat_errata,axis = 1)
    #################
    if 'TCG status' in input_df.columns:
        df['TCG status'] = input_df['TCG status'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'OCG status' in input_df.columns:
        df['OCG status'] = input_df['OCG status'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Modification date' in input_df.columns:
        df['Modification date'] = input_df['Modification date'].dropna().apply(lambda x: pd.Timestamp(int(x[0]['timestamp']), unit='s').ctime() if len(x)>0 else np.nan)
    
    return df

API call functions¶

def card_query(_password = True, _card_type = True, _property = True, _primary = True, _secondary = True, _attribute = True, _monster_type = True, _stars = True, _atk = True, _def = True, _scale = True, _link = True, _arrows = True, _effect_type = True, _archseries = True, _category = True, _tcg = True, _ocg = True, _date = True, _page_name = True):
    search_string = f'|?English%20name=Name'
    if _password:
        search_string += '|?Password'
    if _card_type:
        search_string += '|?Card%20type'
    if _property:    
        search_string += '|?Property'
    if _primary:
        search_string += '|?Primary%20type'
    if _secondary:
        search_string += '|?Secondary%20type'
    if _attribute:
        search_string += '|?Attribute'
    if _monster_type:
        search_string += '|?Type=Monster%20type'
    if _stars:
        search_string += '|?Stars%20string=Level%2FRank%20'
    if _atk:
        search_string += '|?ATK%20string=ATK'
    if _def:
        search_string += '|?DEF%20string=DEF'
    if _scale:
        search_string += '|?Pendulum%20Scale'
    if _link:
        search_string += '|?Link%20Rating=Link'
    if _arrows:
        search_string += '|?Link%20Arrows'
    if _effect_type:
        search_string += '|?Effect%20type'
    if _archseries:
        search_string += '|?Archseries'
    if _category:
        search_string += '|?category'
    if _tcg:
        search_string += '|?TCG%20status'
    if _ocg:
        search_string += '|?OCG%20status'
    if _date:
        search_string += '|?Modification%20date'
    if _page_name:
        search_string += '|?Page%20name'
    
    return search_string

def fetch_spell(spell_query, step = 5000, limit = 5000):
    print('Downloading Spells')
    spell_df = pd.DataFrame()
    for i in range(int(limit/step)):
        df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20Spell%20Cards]]{spell_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
        df = extract_results(df)
        print(f'Iteration {i+1}: {len(df.index)} results')
        spell_df = pd.concat([spell_df, df], ignore_index=True, axis=0)
        if len(df.index)<step:
            break
                
    print(f'- Total\n{len(spell_df.index)} results\n')
    
    return spell_df

def fetch_trap(trap_query, step = 5000, limit = 5000):
    print('Downloading Traps')
    trap_df = pd.DataFrame()
    for i in range(int(limit/step)):    
        df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20Trap%20Cards]]{trap_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
        df = extract_results(df)
        print(f'Iteration {i+1}: {len(df.index)} results')
        trap_df = pd.concat([trap_df, df], ignore_index=True, axis=0)
        if len(df.index)<step:
            break
                
    print(f'- Total\n{len(trap_df.index)} results\n')
    
    return trap_df

def fetch_monster(monster_query, step = 5000, limit = 5000):
    print('Downloading Monsters')
    monster_df = pd.DataFrame()
    for att in attributes:
        print(f"- {att}")
        for i in range(int(limit/step)):
            df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20monsters]][[Attribute::{att}]]{monster_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
            df = extract_results(df)
            print(f'Iteration {i+1}: {len(df.index)} results')
            monster_df = pd.concat([monster_df, df], ignore_index=True, axis=0)
            if len(df.index)<step:
                break
        
    print(f'- Total\n{len(monster_df.index)} results')
    
    return monster_df

def fetch_name_errata(limit = 1000):
    name_query_df = pd.read_json(f'{api_url}?action=ask&query=[[Category:Cards%20with%20name%20errata]]|limit={limit}|order%3Dasc&format=json')
    name_keys = list(name_query_df['query']['results'].keys())
    return pd.DataFrame(True, index = [i.split(':')[1].strip() for i in name_keys if 'Card Errata:' in i], columns = ['Name errata'])

def fetch_type_errata(limit = 1000):
    type_query_df = pd.read_json(f'{api_url}?action=ask&query=[[Category:Cards%20with%20card%20type%20errata]]|limit={limit}|order%3Dasc&format=json')
    type_keys = list(type_query_df['query']['results'].keys())
    return pd.DataFrame(True, index = [i.split(':')[1].strip() for i in type_keys if 'Card Errata:' in i], columns = ['Type errata'])

Data aquisition¶

Fetch online data¶

monster_query = card_query(_property = False)
st_query = card_query(_primary = False, _secondary = False, _attribute = False, _monster_type = False, _stars = False, _atk = False, _def = False, _scale = False, _link = False, _arrows = False)
# Timestamp
timestamp = pd.Timestamp.now().timestamp()
full_df = pd.DataFrame()

# Fetch Spell
spell_df = fetch_spell(st_query, step = 1000, limit = 3000)
full_df = pd.concat([full_df, spell_df], ignore_index=True, axis=0)

# Fetch Trap
trap_df = fetch_trap(st_query, step = 1000, limit = 3000)
full_df = pd.concat([full_df, trap_df], ignore_index=True, axis=0)
st_df = pd.concat([spell_df, trap_df], ignore_index=True, axis=0)

# Fetch Monster
monster_df = fetch_monster(monster_query, step = 1000, limit = 5000)
full_df = pd.concat([full_df, monster_df], ignore_index=True, axis=0)

# Fetch errata
errata_df = pd.concat([fetch_name_errata(), fetch_type_errata()], axis=1).fillna(False)
Downloading Spells
Iteration 1: 1000 results
Iteration 2: 1000 results
Iteration 3: 362 results
- Total
2362 results

Downloading Traps
Iteration 1: 1000 results
Iteration 2: 800 results
- Total
1800 results

Downloading Monsters
- DIVINE
Iteration 1: 9 results
- LIGHT
Iteration 1: 1000 results
Iteration 2: 614 results
- DARK
Iteration 1: 1000 results
Iteration 2: 1000 results
Iteration 3: 210 results
- WATER
Iteration 1: 833 results
- EARTH
Iteration 1: 1000 results
Iteration 2: 867 results
- FIRE
Iteration 1: 665 results
- WIND
Iteration 1: 760 results
- Total
7958 results

Format data¶

formatted_spell_df = format_df(spell_df, errata_df)
formatted_trap_df = format_df(trap_df, errata_df)
formatted_st_df = format_df(st_df, errata_df)
formatted_monster_df = format_df(monster_df, errata_df)
formatted_full_df = format_df(full_df, errata_df)
print('Data formated')
Data formated

Save data¶

formatted_full_df.to_csv(f'Data/All_cards_{int(timestamp)}.csv', index = False)
print('Data saved')
Data saved

Check changes¶

Load latest file¶

# Get list of files
list_of_files = sorted(glob.glob('Data/All_cards_*.csv'), key=os.path.getctime, reverse=True)
# Get second newest file if exist
if len(list_of_files)>1:
    latest_file = list_of_files[1]
    previous_df = pd.read_csv(latest_file, dtype=object)
    # Correct tuples
    previous_df['Effect type'] = previous_df['Effect type'].dropna().apply(literal_eval)
    previous_df['Link Arrows'] = previous_df['Link Arrows'].dropna().apply(literal_eval)
    previous_df['Archseries'] = previous_df['Archseries'].dropna().apply(literal_eval)
    previous_df['Artwork'] = previous_df['Artwork'].dropna().apply(literal_eval)
    previous_df['Errata'] = previous_df['Errata'].dropna().apply(literal_eval)
    print('File loaded')
else:
    print('No older files')
File loaded

Generate changelog¶

if previous_df is not None:
    changelog = previous_df.merge(formatted_full_df,indicator = True, how='outer').loc[lambda x : x['_merge']!='both'].sort_values('Name', ignore_index=True)
    changelog['_merge'].replace(['left_only','right_only'],['Old', 'New'], inplace = True)
    changelog.rename(columns={"_merge": "Version"}, inplace = True)
    nunique = changelog.groupby('Name').nunique()
    cols_to_drop = nunique[nunique < 2].dropna(axis=1).columns
    changelog = changelog.set_index('Name')[nunique > 1]
    changelog.drop(cols_to_drop, axis=1, inplace = True)
    changelog
else:
    print('No changes')

Data visualisation¶

Full data¶

formatted_full_df
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK ... Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
0 "A" Cell Breeding Device 34541863 Spell Card Continuous Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Trigger Effect,) NaN NaN (Name,) Unlimited Unlimited Sat Nov 6 13:57:15 2021
1 "A" Cell Incubator 64163367 Spell Card Continuous Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Continuous-like Effect, Trigger Effect) NaN NaN NaN Unlimited Unlimited Mon Jun 13 04:27:51 2022
2 "A" Cell Recombination Device 91231901 Spell Card Quick-Play Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Effect, Ignition-like Effect) NaN NaN NaN Unlimited Unlimited Thu Mar 12 22:40:14 2020
3 "A" Cell Scatter Burst 73262676 Spell Card Quick-Play Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Effect,) NaN NaN NaN Unlimited Unlimited Sat Nov 6 13:58:32 2021
4 "Infernoble Arms - Durendal" 37478723 Spell Card Equip Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Condition, Ignition-like Effect, Trigger Effect) (Noble Arms,) NaN NaN Unlimited Unlimited Sat Aug 20 13:52:48 2022
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
12115 Yosenju Shinchu L 65025250 Monster Card NaN Effect Monster NaN WIND Rock 4 0 ... 3 NaN NaN (Continuous Effect, Continuous-like Effect, Tr... (Yosenju,) NaN NaN Unlimited Unlimited Sun Aug 14 11:04:00 2022
12116 Yosenju Shinchu R 91420254 Monster Card NaN Effect Monster NaN WIND Rock 4 0 ... 5 NaN NaN (Continuous Effect, Ignition-like Effect, Trig... (Yosenju,) NaN NaN Unlimited Unlimited Sat Aug 13 12:21:48 2022
12117 Yosenju Tsujik 25244515 Monster Card NaN Effect Monster NaN WIND Beast-Warrior 4 1000 ... NaN NaN NaN (Condition, Ignition Effect, Quick Effect, Tri... (Yosenju,) NaN NaN Unlimited Unlimited Sun Dec 20 18:15:02 2020
12118 ZW - Eagle Claw 29353756 Monster Card NaN Effect Monster NaN WIND Winged Beast 5 2000 ... NaN NaN NaN (Continuous-like Effect, Ignition Effect, Uncl... (ZW -, Zexal) NaN NaN Unlimited Unlimited Thu Jul 8 13:48:07 2021
12119 ZW - Tornado Bringer 81471108 Monster Card NaN Effect Monster NaN WIND Dragon 5 1300 ... NaN NaN NaN (Continuous-like Effect, Ignition Effect, Uncl... (ZW -, Zexal) NaN NaN Unlimited Unlimited Sun Aug 14 11:04:24 2022

12120 rows × 21 columns

Card types¶

formatted_full_df.groupby('Card type').nunique()
Name Password Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Card type
Monster Card 7950 7817 0 8 6 7 25 15 82 77 13 6 61 223 984 3 3 7 7 7912
Spell Card 2360 2331 6 0 0 0 0 0 0 0 0 0 0 114 394 3 3 6 6 2350
Trap Card 1800 1779 3 0 0 0 0 0 0 0 0 0 0 95 323 3 3 5 6 1794
card_type_colors = [card_colors[i] for i in formatted_full_df['Card type'].value_counts().index]
formatted_full_df['Card type'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=0, color = card_type_colors)
plt.show()

Monsters¶

Attributes¶

print('Total number of attributes:', formatted_monster_df['Attribute'].nunique())
Total number of attributes: 7
formatted_monster_df.drop(columns=['Card type']).groupby('Attribute').nunique()
Name Password Primary type Secondary type Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Attribute
DARK 2207 2173 7 6 23 14 70 63 12 6 39 153 447 3 3 7 7 2204
DIVINE 6 0 1 0 2 2 3 3 0 0 0 6 3 1 3 2 2 9
EARTH 1865 1840 7 6 23 12 71 60 12 4 29 127 327 3 3 6 6 1861
FIRE 665 657 8 6 22 12 43 40 8 4 22 85 184 3 3 4 6 663
LIGHT 1614 1575 7 6 23 14 58 50 10 5 30 131 381 3 3 6 7 1607
WATER 833 820 7 6 22 11 56 41 9 4 16 92 203 3 3 6 7 833
WIND 760 752 7 6 23 12 46 38 11 4 14 104 211 3 3 6 6 756
attribute_colors = [card_colors[i] for i in formatted_full_df['Attribute'].value_counts().index]
formatted_monster_df['Attribute'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=0, color = attribute_colors)
plt.show()

Primary types¶

print('Total number of primary types:', formatted_monster_df['Primary type'].nunique())
Total number of primary types: 8
formatted_monster_df.drop(columns=['Card type']).groupby('Primary type').nunique()
Name Password Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Primary type
Effect Monster 5400 5345 6 7 25 12 73 66 13 0 0 203 769 3 3 6 6 5374
Fusion Monster 424 419 1 6 23 12 48 46 4 0 0 67 140 3 3 4 6 423
Link Monster 366 358 0 6 23 0 38 0 0 6 61 51 138 3 2 5 5 366
Monster Token 1 0 0 1 1 1 1 1 0 0 0 0 1 0 0 0 1 1
Normal Monster 745 701 1 6 23 10 59 49 10 0 0 6 129 3 3 4 4 746
Ritual Monster 119 117 3 6 15 12 33 26 1 0 0 33 37 2 3 2 2 119
Synchro Monster 410 400 1 6 23 13 40 38 4 0 0 56 155 2 3 5 5 410
Xyz Monster 489 477 0 6 23 14 51 42 4 0 0 68 190 3 2 5 5 487

Has effect discrimination¶

has_effect = formatted_monster_df['Primary type'].where(formatted_monster_df['Effect type'].notna()).value_counts().rename('Effect')
no_effect = formatted_monster_df['Primary type'].where(formatted_monster_df['Effect type'].isna()).value_counts().rename('No Effect')
effect = pd.concat([has_effect,no_effect], axis=1)
effect
Effect No Effect
Effect Monster 5399.0 1
Xyz Monster 487.0 2
Synchro Monster 407.0 3
Fusion Monster 362.0 62
Link Monster 360.0 6
Ritual Monster 103.0 16
Normal Monster 34.0 712
Monster Token NaN 1
monster_type_colors = {'No Effect': card_colors['Normal Monster'], 'Effect': [card_colors[i] for i in effect.index]}
effect.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0,  legend=True, color = monster_type_colors)
plt.show()

Normal monster can have effect if it is pendulum

Is pendulum discrimination¶

not_pendulum = formatted_monster_df['Primary type'].where(formatted_monster_df['Pendulum Scale'].isna()).value_counts().rename('Not Pendulum')
is_pendulum = formatted_monster_df['Primary type'].where(formatted_monster_df['Pendulum Scale'].notna()).value_counts().rename('Pendulum')
pendulum = pd.concat([not_pendulum,is_pendulum], axis=1)
pendulum
Not Pendulum Pendulum
Effect Monster 5138 262.0
Normal Monster 708 38.0
Xyz Monster 482 7.0
Fusion Monster 414 10.0
Synchro Monster 404 6.0
Link Monster 366 NaN
Ritual Monster 118 1.0
Monster Token 1 NaN
monster_type_colors_b = {'Pendulum': card_colors['Pendulum Monster'], 'Not Pendulum': [card_colors[i] for i in pendulum.index]}
pendulum.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0, color = monster_type_colors_b, legend=True)
plt.show()

By attribute¶

primmary_crosstab = pd.crosstab(formatted_full_df['Primary type'],formatted_full_df['Attribute'])
primmary_crosstab
Attribute DARK DIVINE EARTH FIRE LIGHT WATER WIND
Primary type
Effect Monster 1483 6 1296 450 1089 550 526
Fusion Monster 146 0 81 34 96 34 33
Link Monster 119 0 74 33 86 29 25
Monster Token 0 0 0 1 0 0 0
Normal Monster 186 0 250 52 82 109 67
Ritual Monster 35 0 17 7 34 20 6
Synchro Monster 107 0 69 50 74 36 74
Xyz Monster 134 0 80 38 153 55 29
plt.figure(figsize = (16,10))
sns.heatmap(primmary_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Secondary types¶

print('Total number of secondary types:', formatted_monster_df['Secondary type'].nunique())
Total number of secondary types: 6
formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Secondary type').nunique()
Name Password Primary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Effect type Archseries Artwork Errata TCG status OCG status Modification date
Secondary type
Flip monster 183 182 2 6 19 12 38 33 1 20 45 2 3 4 4 183
Gemini monster 45 45 1 6 18 8 17 19 0 6 13 0 3 1 1 45
Spirit monster 37 37 2 6 13 9 22 20 2 7 4 1 1 3 2 37
Toon monster 17 17 1 6 7 5 12 15 0 8 13 1 2 1 2 17
Tuner monster 466 461 5 6 23 9 32 32 7 57 131 3 3 4 4 465
Union monster 37 37 1 6 9 8 17 14 0 6 9 1 2 1 1 37
secondary_type_colors = card_colors['Effect Monster']
formatted_monster_df['Secondary type'].value_counts().plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0, color = secondary_type_colors, legend=True)
plt.show()

By attribute¶

secondary_crosstab = pd.crosstab(formatted_full_df['Secondary type'],formatted_full_df['Attribute'])
secondary_crosstab
Attribute DARK EARTH FIRE LIGHT WATER WIND
Secondary type
Flip monster 51 61 10 31 13 17
Gemini monster 11 8 8 6 8 4
Spirit monster 5 6 6 4 6 10
Toon monster 7 5 1 2 1 1
Tuner monster 119 91 42 94 51 69
Union monster 6 9 3 12 4 3
plt.figure(figsize = (8,6))
sns.heatmap(secondary_crosstab, annot=True, fmt="g", cmap='viridis', square=True)
plt.show()

By secondary type¶

secondary_crosstab_b = pd.crosstab(formatted_full_df['Primary type'],formatted_full_df['Secondary type'], margins = True)
secondary_crosstab_b
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster All
Primary type
Effect Monster 182 45 35 17 420 37 736
Fusion Monster 0 0 0 0 3 0 3
Normal Monster 0 0 0 0 12 0 12
Ritual Monster 1 0 2 0 1 0 4
Synchro Monster 0 0 0 0 30 0 30
All 183 45 37 17 466 37 785
plt.figure(figsize = (10,7))
sns.heatmap(secondary_crosstab_b, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Monster types¶

print('Total number of monster types:', formatted_monster_df['Monster type'].nunique())
Total number of monster types: 25
formatted_monster_df.drop(columns=['Card type']).groupby('Monster type').nunique()
Name Password Primary type Secondary type Attribute Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Monster type
Aqua 255 252 7 6 6 10 50 33 3 2 3 50 64 2 3 5 6 255
Beast 376 368 7 4 6 10 48 38 7 2 7 59 84 3 3 5 5 377
Beast-Warrior 236 232 7 3 6 10 36 29 6 3 7 57 47 3 3 5 5 235
Creator God 1 0 1 0 1 1 1 1 0 0 0 1 1 0 0 0 1 1
Cyberse 246 244 7 1 6 11 30 29 1 6 38 45 34 2 2 4 4 246
Dinosaur 122 120 6 1 6 10 35 30 4 2 3 35 24 1 2 4 3 122
Divine-Beast 5 0 1 0 1 1 3 3 0 0 0 5 2 1 3 2 2 8
Dragon 655 648 7 6 6 13 52 48 9 5 19 109 184 2 3 6 6 652
Fairy 509 497 7 5 6 12 43 38 9 4 12 80 110 3 3 6 6 506
Fiend 763 746 7 6 6 13 60 45 12 5 14 106 147 3 3 6 6 763
Fish 127 121 7 2 5 10 34 28 1 1 1 30 21 2 2 3 3 127
Insect 243 236 7 3 6 12 45 34 2 3 6 58 39 2 2 3 3 243
Machine 915 900 7 5 6 12 62 55 9 4 22 111 167 3 3 6 7 910
Plant 231 228 6 4 6 9 37 30 5 4 9 38 38 2 2 4 5 231
Psychic 177 173 6 2 6 11 35 31 5 2 3 42 42 1 2 5 5 177
Pyro 121 120 7 5 5 11 34 29 0 1 1 36 33 1 3 1 3 121
Reptile 171 170 6 3 6 11 37 30 3 2 3 46 35 0 2 4 3 171
Rock 247 244 7 4 6 11 43 40 4 3 4 60 73 1 3 5 6 246
Sea Serpent 82 82 6 3 6 10 28 26 1 2 2 32 28 2 3 3 2 82
Spellcaster 674 662 7 5 6 12 50 41 10 5 12 100 146 3 3 6 7 672
Thunder 128 125 6 4 6 10 35 29 1 2 4 37 33 1 2 4 4 128
Warrior 1024 1015 7 6 6 13 60 41 6 3 15 92 215 3 3 7 7 1022
Winged Beast 313 309 7 5 6 10 39 29 4 4 6 61 65 2 3 5 5 313
Wyrm 87 85 6 1 6 11 26 24 3 4 6 33 20 1 1 3 3 87
Zombie 242 240 7 5 6 12 38 37 1 3 5 51 35 2 3 2 2 241
monster_type_colors = card_colors['Monster Card']
formatted_monster_df['Monster type'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=45, color = monster_type_colors)
plt.show()

By Attribute¶

monster_crosstab = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Attribute'], dropna=False)
monster_crosstab
Attribute DARK DIVINE EARTH FIRE LIGHT WATER WIND
Monster type
Aqua 9 0 6 10 4 220 6
Beast 37 0 213 16 72 14 25
Beast-Warrior 37 0 82 53 33 16 15
Creator God 0 1 0 0 0 0 0
Cyberse 63 0 36 44 63 28 12
Dinosaur 11 0 60 32 5 8 6
Divine-Beast 0 8 0 0 0 0 0
Dragon 252 0 47 48 167 28 113
Fairy 55 0 62 17 324 26 25
Fiend 575 0 34 47 70 23 16
Fish 2 0 2 0 1 120 2
Insect 37 0 132 6 20 4 44
Machine 224 0 309 51 167 48 116
Plant 42 0 118 11 22 24 14
Psychic 23 0 37 17 45 13 42
Pyro 2 0 6 106 4 0 3
Reptile 39 0 34 15 45 34 4
Rock 16 0 199 5 15 5 7
Sea Serpent 3 0 1 1 2 71 4
Spellcaster 281 0 53 28 188 63 62
Thunder 13 0 10 5 77 4 19
Warrior 203 0 363 101 245 53 60
Winged Beast 110 0 7 16 15 12 153
Wyrm 15 0 18 11 23 12 8
Zombie 161 0 38 25 7 7 4
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True)
plt.show()

By primary type¶

monster_crosstab_b = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Primary type'], dropna=False)
monster_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Monster Token Normal Monster Ritual Monster Synchro Monster Xyz Monster
Monster type
Aqua 153 11 3 0 59 8 4 17
Beast 271 17 9 0 54 1 14 11
Beast-Warrior 162 11 9 0 21 2 8 23
Creator God 1 0 0 0 0 0 0 0
Cyberse 122 4 93 0 7 6 5 9
Dinosaur 87 7 3 0 18 0 4 3
Divine-Beast 5 0 0 0 0 0 0 0
Dragon 346 62 33 0 46 15 93 60
Fairy 362 21 24 0 36 17 17 32
Fiend 534 46 28 0 79 15 23 40
Fish 91 5 1 0 17 1 9 3
Insect 180 3 9 0 29 1 7 14
Machine 633 47 38 0 67 4 61 65
Plant 161 6 15 0 25 0 8 16
Psychic 120 11 5 0 9 0 19 13
Pyro 84 8 1 1 18 0 5 4
Reptile 140 1 3 0 19 0 5 3
Rock 169 18 4 0 28 7 5 16
Sea Serpent 55 2 2 0 8 0 5 10
Spellcaster 510 25 26 0 55 18 16 25
Thunder 97 8 5 0 11 0 5 2
Warrior 672 94 29 0 80 14 54 82
Winged Beast 227 8 10 0 27 4 15 22
Wyrm 55 2 9 0 3 0 10 8
Zombie 163 7 7 0 30 6 18 11
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square=True, norm = LogNorm())
plt.show()

By secondary type¶

monster_crosstab_c = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Secondary type'], dropna=False)
monster_crosstab_c
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster
Monster type
Aqua 4 4 1 1 10 3
Beast 15 1 2 0 22 0
Beast-Warrior 1 0 1 0 9 0
Cyberse 0 0 0 0 6 0
Dinosaur 0 0 0 0 7 0
Dragon 1 6 1 3 42 4
Fairy 8 2 7 0 20 5
Fiend 27 4 2 1 41 1
Fish 0 1 0 0 8 0
Insect 20 2 0 0 12 0
Machine 10 1 0 4 80 18
Plant 4 1 0 0 20 1
Psychic 3 0 0 0 23 0
Pyro 4 2 2 0 8 1
Reptile 18 1 0 0 7 0
Rock 11 1 2 0 3 0
Sea Serpent 1 1 0 0 9 0
Spellcaster 33 3 4 4 39 0
Thunder 3 1 1 0 8 0
Warrior 11 9 5 3 30 3
Winged Beast 5 2 7 1 30 0
Wyrm 0 0 0 0 10 0
Zombie 4 3 2 0 22 1
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab_c.T, annot=True, fmt="g", cmap='viridis', square=True, norm = LogNorm())
plt.show()

Effect type¶

print('Total number of effect types:', formatted_monster_df['Effect type'].explode().nunique())
Total number of effect types: 14
formatted_monster_df[formatted_monster_df['Effect type'].notna()].drop(columns=['Card type']).explode('Effect type').groupby('Effect type').nunique()
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Archseries Artwork Errata TCG status OCG status Modification date
Effect type
Activation condition 1 1 1 0 1 1 1 1 1 1 0 0 1 0 0 1 1 1
Condition 3032 2954 7 6 7 25 14 63 63 13 5 53 634 3 3 5 6 3021
Continuous Effect 2136 2116 6 5 7 24 14 59 52 12 6 48 555 3 3 4 4 2133
Continuous-like Effect 234 233 6 3 6 21 11 42 36 13 1 2 72 2 3 4 3 234
Flip effect 169 168 1 1 6 19 12 38 33 1 0 0 43 2 3 3 4 169
Ignition Effect 2582 2555 6 6 7 24 13 66 61 12 5 42 632 3 3 5 6 2575
Ignition-like Effect 216 208 6 2 6 20 12 35 32 13 1 1 74 1 3 4 6 216
Lingering effect 17 16 2 1 6 12 7 12 14 0 2 2 10 0 0 2 3 17
Maintenance cost 44 44 3 0 6 12 8 21 18 2 1 1 8 0 1 1 1 44
Quick Effect 1004 992 6 4 6 23 13 50 47 9 5 28 387 3 3 4 5 1002
Quick-like Effect 4 4 1 0 1 1 1 3 2 0 0 0 1 0 0 1 1 4
Summoning condition 913 865 6 4 7 25 13 52 51 8 5 6 314 3 3 5 6 909
Trigger Effect 4283 4241 7 6 7 24 14 66 62 13 5 49 756 3 3 4 6 4264
Unclassified effect 808 796 6 5 7 25 13 49 45 9 5 12 272 3 3 4 4 805
monster_effect_colors = card_colors['Effect Monster']
formatted_monster_df['Effect type'].explode('Effect type').value_counts().plot.bar(figsize = (18,6), grid = True, color = monster_effect_colors)
plt.show()

ATK¶

print('Total number of ATK values:', formatted_monster_df['ATK'].nunique())
Total number of ATK values: 82
formatted_monster_df.drop(columns=['Card type']).groupby('ATK').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
ATK
0 611 584 8 5 6 23 13 35 9 5 15 92 233 3 3 6 6 610
50 2 2 1 0 2 2 1 2 0 0 0 2 2 0 0 1 1 2
100 217 216 5 3 6 20 11 27 8 2 2 48 107 2 3 4 3 217
150 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1
200 118 117 6 5 6 20 7 21 4 1 2 34 67 2 3 3 3 118
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4500 12 12 3 0 3 6 4 4 0 0 0 10 9 1 1 1 1 12
4600 2 2 1 0 2 1 1 1 0 0 0 2 1 0 0 1 1 2
5000 9 9 5 0 3 4 2 4 0 1 1 8 6 1 1 1 1 9
? 83 75 6 1 7 20 15 8 2 1 1 34 36 2 3 4 4 84
X000 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 1 1

82 rows × 18 columns

atk_colors = card_colors['Monster Card']
formatted_monster_df['DEF'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, color = atk_colors)
plt.show()

DEF¶

print('Total number of DEF values:', formatted_monster_df['DEF'].nunique())
Total number of DEF values: 77
formatted_monster_df.drop(columns=['Card type']).groupby('DEF').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
DEF
0 768 737 7 6 6 23 14 45 10 0 0 104 258 3 3 5 5 765
50 1 1 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 1
100 208 207 5 4 6 19 10 24 8 0 0 46 95 2 3 3 4 207
200 249 246 5 5 6 23 10 31 5 0 0 47 108 3 3 4 5 249
250 8 8 2 1 4 5 2 4 0 0 0 5 3 0 1 1 1 8
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4500 2 2 2 0 2 2 1 1 0 0 0 2 1 0 0 1 1 2
4800 1 1 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 1
5000 5 5 2 0 3 3 2 2 0 0 0 4 3 1 1 1 1 5
? 56 49 5 1 7 17 14 2 1 0 0 25 25 2 3 4 4 57
X000 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 1 1

77 rows × 18 columns

def_colors = card_colors['Monster Card']
formatted_monster_df['DEF'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, color = def_colors)
plt.show()

Level/Rank¶

formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Level/Rank').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type ATK DEF Pendulum Scale Effect type Archseries Artwork Errata TCG status OCG status Modification date
Level/Rank
0 6 6 2 0 2 2 3 3 0 5 3 0 0 2 2 6
1 627 601 7 5 6 23 22 29 10 80 227 3 3 5 5 625
2 672 662 6 5 6 23 29 30 7 74 213 3 3 5 6 671
3 1144 1136 6 5 6 23 41 36 9 92 290 3 3 5 7 1144
4 2326 2312 6 6 6 23 54 47 9 134 505 3 3 5 7 2319
5 593 591 6 6 6 23 46 38 8 83 234 3 3 4 4 593
6 606 597 6 6 6 23 38 38 9 92 233 3 3 6 6 607
7 467 457 6 6 6 23 38 35 9 100 225 3 3 5 6 468
8 671 648 6 5 6 23 42 41 8 111 298 3 3 5 6 672
9 143 138 5 2 6 21 31 27 1 55 85 1 3 5 4 143
10 245 232 5 2 7 22 32 33 6 76 146 2 3 4 4 248
11 31 30 6 2 6 13 16 17 1 22 23 0 1 3 2 31
12 51 48 5 1 6 12 12 16 2 32 38 1 2 2 3 51
13 1 1 1 0 1 1 1 1 0 1 1 0 0 1 1 1
? 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1
stars_colors = card_colors['Level']
formatted_monster_df['Level/Rank'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color= stars_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Level/Rank','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Level/Rank').describe()
ATK
count mean std min 25% 50% 75% max
Level/Rank
0 5.0 600.000000 1341.640786 0.0 0.0 0.0 0.0 3000.0
1 617.0 239.789303 352.151718 0.0 0.0 100.0 300.0 2500.0
2 670.0 581.716418 409.369938 0.0 300.0 500.0 800.0 2400.0
3 1141.0 959.027169 485.041163 0.0 600.0 1000.0 1300.0 3000.0
4 2314.0 1418.725151 539.719843 0.0 1200.0 1500.0 1800.0 3000.0
5 590.0 1765.711864 637.542570 0.0 1500.0 1900.0 2200.0 4000.0
6 603.0 2015.174129 613.522395 0.0 1900.0 2200.0 2400.0 4000.0
7 463.0 2284.773218 619.488951 0.0 2200.0 2500.0 2600.0 3300.0
8 663.0 2548.340875 706.682791 0.0 2500.0 2800.0 3000.0 4500.0
9 140.0 2601.785714 842.196740 0.0 2500.0 2800.0 3000.0 4500.0
10 225.0 2825.111111 1216.938896 0.0 2800.0 3000.0 3500.0 5000.0
11 30.0 2990.000000 1093.113238 0.0 3000.0 3350.0 3500.0 4000.0
12 47.0 3361.702128 1402.723003 0.0 3000.0 4000.0 4000.0 5000.0

DEF statistics¶

formatted_monster_df[['Level/Rank','DEF']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Level/Rank').describe()
DEF
count mean std min 25% 50% 75% max
Level/Rank
0 5.0 400.000000 894.427191 0.0 0.0 0.0 0.0 2000.0
1 619.0 337.883683 519.434793 0.0 0.0 100.0 400.0 2500.0
2 671.0 660.506706 555.062761 0.0 200.0 500.0 900.0 2400.0
3 1141.0 955.740578 571.578224 0.0 600.0 900.0 1300.0 3000.0
4 2316.0 1169.054404 606.786682 0.0 800.0 1200.0 1600.0 3000.0
5 591.0 1423.688663 673.001321 0.0 1000.0 1500.0 1900.0 3000.0
6 603.0 1556.268657 711.873323 0.0 1200.0 1700.0 2000.0 3000.0
7 465.0 1886.666667 653.772760 0.0 1600.0 2000.0 2300.0 3300.0
8 670.0 1976.268657 848.089977 0.0 1600.0 2100.0 2500.0 4000.0
9 140.0 2315.357143 790.134685 0.0 2000.0 2500.0 2925.0 3700.0
10 234.0 2227.564103 1279.912000 0.0 1825.0 2500.0 3000.0 5000.0
11 30.0 2661.666667 1169.415071 0.0 2125.0 3000.0 3400.0 4000.0
12 48.0 2879.166667 1644.586003 0.0 2000.0 3350.0 4000.0 5000.0

Pendulum scale¶

formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Pendulum Scale').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Effect type Archseries Artwork Errata TCG status OCG status Modification date
Pendulum Scale
0 10 10 2 1 5 7 6 5 5 8 8 1 0 1 1 10
1 68 64 5 2 6 10 11 28 26 37 39 0 1 4 5 68
2 36 36 2 1 6 11 6 17 22 21 15 0 2 4 2 36
3 36 36 2 1 6 15 8 22 15 23 17 0 0 1 1 36
4 32 32 5 0 5 8 8 18 16 25 16 1 1 1 1 32
5 34 34 2 1 6 12 7 23 21 20 16 0 1 3 3 34
6 15 15 1 1 4 7 6 11 11 11 9 0 0 2 1 15
7 27 27 2 1 6 14 6 19 17 14 16 0 2 2 1 27
8 40 39 5 1 6 9 8 19 18 23 21 0 0 1 4 40
9 8 8 2 1 3 3 5 3 2 5 3 0 0 2 1 8
10 14 11 5 0 6 6 5 6 8 11 8 0 0 2 2 14
12 3 2 2 0 2 3 2 3 3 3 3 0 0 1 2 3
13 1 1 1 0 1 1 1 1 1 1 1 0 0 1 1 1
scales_colors = card_colors['Pendulum Monster']
formatted_monster_df['Pendulum Scale'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color = scales_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Pendulum Scale','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
ATK
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 1390.000000 1317.784336 0.0 0.0 1450.0 2500.0 3000.0
1 67.0 1747.761194 1045.822601 0.0 1000.0 1800.0 2500.0 4000.0
2 36.0 1423.611111 688.734462 100.0 800.0 1500.0 2000.0 2500.0
3 36.0 1437.500000 845.354955 0.0 600.0 1725.0 2025.0 2600.0
4 32.0 1787.500000 1011.785391 0.0 1100.0 2000.0 2550.0 3000.0
5 34.0 1339.705882 808.831875 0.0 850.0 1325.0 1800.0 3450.0
6 15.0 1320.000000 707.308783 100.0 950.0 1500.0 1800.0 2400.0
7 27.0 1279.629630 787.920737 0.0 700.0 1400.0 1750.0 3000.0
8 40.0 1232.500000 957.129121 0.0 300.0 1200.0 2000.0 3300.0
9 8.0 2150.000000 730.948503 1000.0 2050.0 2400.0 2500.0 2800.0
10 14.0 1678.571429 1376.829452 0.0 125.0 2500.0 2875.0 3000.0
12 2.0 1550.000000 2050.609665 100.0 825.0 1550.0 2275.0 3000.0
13 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

DEF statistics¶

formatted_monster_df[['Pendulum Scale','DEF']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
DEF
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 1200.000000 1273.664878 0.0 0.0 750.0 2500.0 3000.0
1 68.0 1592.647059 949.204880 0.0 975.0 1750.0 2400.0 4000.0
2 36.0 1338.888889 728.316171 0.0 875.0 1200.0 1825.0 2700.0
3 36.0 1165.277778 788.834533 0.0 575.0 1200.0 1800.0 3000.0
4 32.0 1534.375000 830.316448 0.0 1000.0 1600.0 2075.0 2800.0
5 34.0 1136.764706 822.625953 0.0 550.0 1000.0 1575.0 3000.0
6 15.0 1226.666667 711.604492 400.0 600.0 1100.0 1700.0 2600.0
7 27.0 1312.962963 830.383669 0.0 700.0 1300.0 2000.0 2700.0
8 40.0 1027.500000 783.479255 0.0 375.0 1000.0 1700.0 2700.0
9 8.0 1225.000000 636.396103 1000.0 1000.0 1000.0 1000.0 2800.0
10 14.0 1850.000000 1124.380171 0.0 750.0 2500.0 2575.0 3000.0
12 2.0 1550.000000 2050.609665 100.0 825.0 1550.0 2275.0 3000.0
13 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

Level/Rank statistics¶

formatted_monster_df[['Pendulum Scale','Level/Rank']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
Level/Rank
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 6.100000 3.348300 1.0 3.75 7.0 8.00 10.0
1 68.0 5.985294 2.421870 1.0 4.00 6.0 8.00 12.0
2 36.0 4.416667 1.380993 1.0 3.75 4.0 5.00 7.0
3 36.0 4.444444 1.731134 1.0 4.00 4.0 5.00 10.0
4 32.0 5.562500 2.154328 1.0 4.00 6.0 7.00 8.0
5 34.0 4.176471 1.961301 1.0 3.00 4.0 4.00 11.0
6 15.0 3.933333 1.579632 1.0 3.00 4.0 4.50 8.0
7 27.0 4.185185 1.641693 2.0 3.00 4.0 5.00 10.0
8 40.0 3.925000 2.324755 1.0 2.00 4.0 6.00 10.0
9 8.0 5.625000 1.302470 4.0 5.00 5.0 6.25 8.0
10 14.0 6.714286 2.812843 1.0 7.00 7.0 7.75 10.0
12 3.0 8.333333 6.350853 1.0 6.50 12.0 12.00 12.0
13 1.0 7.000000 NaN 7.0 7.00 7.0 7.00 7.0

Link¶

formatted_monster_df.drop(columns=['Card type', 'Primary type', 'Secondary type','Level/Rank','DEF','Pendulum Scale']).groupby('Link').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Attribute Monster type ATK Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link
1 47 47 6 11 10 8 17 26 1 0 3 3 47
2 184 183 6 23 23 19 31 102 1 2 3 4 184
3 81 81 6 16 17 17 25 46 2 1 2 2 81
4 44 41 6 16 12 13 21 24 2 0 4 4 44
5 9 5 2 5 4 3 6 5 0 0 2 3 9
6 1 1 1 1 1 1 1 1 0 0 1 1 1
link_colors = card_colors['Link Monster']
formatted_monster_df['Link'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color = link_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Link','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Link').describe()
ATK
count mean std min 25% 50% 75% max
Link
1 47.0 736.170213 482.937358 0.0 400.0 800.0 1000.0 1500.0
2 184.0 1400.815217 508.170283 0.0 1100.0 1500.0 1800.0 2300.0
3 81.0 2258.641975 659.487970 0.0 2200.0 2400.0 2500.0 4000.0
4 43.0 2660.465116 653.976676 0.0 2500.0 2800.0 3000.0 3300.0
5 9.0 3277.777778 712.000312 2500.0 3000.0 3000.0 3500.0 5000.0
6 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

Link Arrows¶

By combination¶

print('Total number of link arrow combinations:', formatted_monster_df['Link Arrows'].nunique())
Total number of link arrow combinations: 61
formatted_monster_df.drop(columns=['Card type', 'Primary type', 'Level/Rank', 'Pendulum Scale', 'Link', 'Secondary type', 'DEF']).groupby('Link Arrows').nunique()
Name Password Attribute Monster type ATK Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link Arrows
(←,) 5 5 2 3 2 4 4 0 0 3 2 5
(←, ↑) 4 4 2 3 4 3 2 0 0 1 1 4
(←, →) 18 18 6 8 11 8 9 0 0 2 2 18
(←, →, ↑) 7 7 3 5 6 6 5 0 0 1 1 7
(↑,) 10 10 5 5 6 9 5 0 0 1 1 10
... ... ... ... ... ... ... ... ... ... ... ... ...
(↙, ↘, ←, ↖) 1 1 1 1 1 1 1 0 0 1 1 1
(↙, ↘, ↑) 22 22 6 11 11 11 15 1 1 2 2 22
(↙, ↘, →) 2 2 2 2 2 2 2 0 0 1 1 2
(↙, ↘, ↖) 2 2 2 2 2 2 0 0 0 1 1 2
(↙, ↘, ↖, ↗) 1 1 1 1 1 1 1 0 0 1 1 1

61 rows × 12 columns

arrows_colors = card_colors['Link Monster']
formatted_monster_df['Link Arrows'].value_counts().plot.bar(figsize = (18,6), logy=True, grid = True, color = arrows_colors)
plt.show()

By unique¶

formatted_monster_df[formatted_monster_df['Link Arrows'].notna()].drop(columns=['Card type', 'Primary type', 'Level/Rank', 'Pendulum Scale', 'Secondary type', 'DEF']).explode('Link Arrows').groupby('Link Arrows').nunique()
Name Password Attribute Monster type ATK Link Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link Arrows
← 114 107 6 21 29 6 34 45 2 0 5 4 114
↑ 114 111 6 19 27 6 31 44 2 1 4 4 114
→ 100 93 6 19 27 6 29 40 2 0 4 4 100
↓ 157 150 6 20 31 6 41 68 3 0 4 5 157
↖ 10 10 5 5 9 4 6 5 1 0 1 2 10
↗ 15 15 5 7 10 5 7 7 0 0 2 2 15
↘ 186 181 6 22 32 6 35 103 3 2 4 5 186
↙ 189 184 6 22 33 6 37 104 3 2 4 5 189
arrows_colors_b = card_colors['Link Monster']
formatted_monster_df['Link Arrows'].explode('Link Arrows').value_counts().plot.bar(figsize = (18,6), grid = True, color = arrows_colors_b)
plt.show()

By link¶

arrow_per_link = formatted_monster_df[['Link Arrows','Link']].explode('Link Arrows').dropna()
arrow_crosstab = pd.crosstab(arrow_per_link['Link Arrows'],arrow_per_link['Link'])
arrow_crosstab
Link 1 2 3 4 5 6
Link Arrows
← 5 47 23 30 8 1
↑ 10 28 43 28 4 1
→ 2 33 24 31 9 1
↓ 18 59 41 32 6 1
↖ 1 2 5 2 0 0
↗ 3 5 3 3 1 0
↘ 3 95 53 25 9 1
↙ 5 99 51 25 8 1
plt.figure(figsize = (10,6))
sns.heatmap(arrow_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Spell & Trap¶

Properties¶

print('Total number of properties:', formatted_st_df['Property'].nunique())
Total number of properties: 9
formatted_st_df.drop(columns=['Card type']).groupby('Property').nunique()
Name Password Effect type Archseries Artwork Errata TCG status OCG status Modification date
Property
Continuous Spell Card 418 412 53 158 3 3 6 5 416
Continuous Trap Card 488 479 63 161 2 3 4 2 488
Counter Trap Card 154 152 19 58 2 2 3 2 154
Equip Spell Card 262 262 37 74 1 3 3 2 262
Field Spell Card 272 266 35 144 2 3 5 4 273
Normal Spell Card 911 902 43 228 3 3 5 6 910
Normal Trap Card 1158 1148 48 238 3 2 5 6 1154
Quick-Play Spell Card 422 415 34 139 3 3 3 4 421
Ritual Spell Card 75 74 8 25 2 2 2 2 75
st_colors = [card_colors[i] for i in formatted_full_df[['Card type','Property']].value_counts().index.get_level_values(0)]
formatted_st_df['Property'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=45, color = st_colors)
plt.show()

Effect type¶

print('Total number of effect types:', formatted_st_df['Effect type'].explode().nunique())
Total number of effect types: 14
formatted_st_df.explode('Effect type').groupby('Effect type').nunique()
Name Password Card type Property Archseries Artwork Errata TCG status OCG status Modification date
Effect type
Activation condition 832 825 2 8 171 3 3 5 5 831
Condition 1655 1622 2 9 368 3 3 6 5 1645
Continuous Effect 21 21 2 6 12 0 2 1 1 21
Continuous-like Effect 893 883 2 7 236 3 3 6 5 893
Cost 452 450 2 7 112 3 3 5 4 452
Effect 2908 2872 2 9 426 3 3 6 6 2895
Ignition Effect 2 2 2 2 2 0 0 1 1 2
Ignition-like Effect 431 425 1 6 180 1 2 4 5 430
Lingering effect 94 94 2 6 41 2 2 3 3 94
Maintenance cost 22 22 2 5 7 1 1 3 2 22
Quick Effect 9 9 2 3 4 0 0 1 1 9
Quick-like Effect 332 326 2 4 147 2 1 4 5 332
Trigger Effect 840 824 2 9 257 2 3 4 5 834
Unclassified effect 83 83 2 9 48 1 0 2 2 82

Spell & Trap discrimination¶

spell = formatted_spell_df['Effect type'].explode('Effect type').value_counts().rename('Spell Card')
trap = formatted_trap_df['Effect type'].explode('Effect type').value_counts().rename('Trap Card')
st_diff = pd.concat([spell, trap], axis = 1)
st_diff
Spell Card Trap Card
Effect 1514 1395.0
Condition 1123 533.0
Continuous-like Effect 614 280.0
Trigger Effect 564 276.0
Ignition-like Effect 431 NaN
Activation condition 244 588.0
Cost 241 211.0
Unclassified effect 63 20.0
Lingering effect 56 38.0
Maintenance cost 11 11.0
Continuous Effect 7 14.0
Quick Effect 4 5.0
Quick-like Effect 3 329.0
Ignition Effect 1 1.0
st_diff_colors = {'Spell Card': card_colors['Spell Card'], 'Trap Card': card_colors['Trap Card']}
st_diff.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=45, color = st_diff_colors)
plt.show()

Archseries¶

exploded_archseries = formatted_full_df.explode('Archseries')
print('Total number of Archseries:', exploded_archseries['Archseries'].nunique())
Total number of Archseries: 710
exploded_archseries.groupby('Archseries').nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Artwork Errata TCG status OCG status Modification date
Archseries
"C" 9 8 1 0 2 0 1 1 8 9 8 0 0 0 7 0 1 2 2 9
-Eyes Dragon 72 71 1 0 7 2 6 3 10 16 13 6 1 1 44 1 3 2 3 71
/Assault Mode 7 7 1 0 1 0 5 6 5 6 6 0 0 0 5 0 0 1 1 7
@Ignister 18 18 1 0 6 1 6 1 7 10 9 0 3 4 9 0 0 1 1 18
A-to-Z 16 16 1 0 3 1 1 1 4 13 12 0 0 0 5 2 3 1 2 16
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
sphinx 10 10 2 1 1 0 2 2 4 8 5 0 0 0 9 0 0 1 1 10
sprout 2 2 1 0 1 0 1 1 1 1 1 0 0 0 2 0 0 1 1 2
tellarknight 21 21 2 3 2 0 2 3 2 16 14 2 0 0 11 0 0 2 2 21
with Chain 4 4 1 1 0 0 0 0 0 0 0 0 0 0 4 1 0 1 1 4
with Eyes of Blue 8 8 2 2 1 1 1 1 1 3 4 0 0 0 6 0 1 1 1 8

710 rows × 20 columns

exploded_archseries['Archseries'].value_counts().plot.barh(figsize = (10,200), grid = True)
plt.show()

By card type¶

archseries_crosstab = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Card type'], margins = True)
archseries_crosstab
Card type Monster Card Spell Card Trap Card All
Archseries
"C" 9 0 0 9
-Eyes Dragon 72 0 0 72
/Assault Mode 7 0 0 7
@Ignister 18 0 0 18
A-to-Z 16 0 0 16
... ... ... ... ...
sprout 2 0 0 2
tellarknight 17 4 0 21
with Chain 0 0 4 4
with Eyes of Blue 5 3 0 8
All 7263 1351 891 9505

711 rows × 4 columns

By primary type¶

archseries_crosstab_b = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Primary type'], margins = True)
archseries_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Monster Token Normal Monster Ritual Monster Synchro Monster Xyz Monster All
Archseries
"C" 8 0 0 0 1 0 0 0 9
-Eyes Dragon 31 11 1 0 3 4 5 17 72
/Assault Mode 7 0 0 0 0 0 0 0 7
@Ignister 10 1 4 0 0 1 1 1 18
A-to-Z 6 8 0 0 2 0 0 0 16
... ... ... ... ... ... ... ... ... ...
sphinx 9 0 0 0 0 0 0 0 9
sprout 2 0 0 0 0 0 0 0 2
tellarknight 12 0 0 0 0 0 0 5 17
with Eyes of Blue 5 0 0 0 0 0 0 0 5
All 4661 532 333 1 244 120 437 931 7259

647 rows × 9 columns

By secondary type¶

archseries_crosstab_c = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Secondary type'], margins = True)
archseries_crosstab_c
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster All
Archseries
-Eyes Dragon 0 2 0 2 0 0 4
@Ignister 0 0 0 0 1 0 1
A-to-Z 0 0 0 0 0 6 6
Adamancipator 0 0 0 0 3 0 3
Alien 1 1 0 0 1 0 3
... ... ... ... ... ... ... ...
itsu 0 0 0 0 0 2 2
lswarm 2 0 0 0 0 0 2
roid 0 0 0 0 9 0 9
with Eyes of Blue 0 0 0 0 5 0 5
All 126 28 13 36 415 18 636

196 rows × 7 columns

By monster type¶

archseries_crosstab_d = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Monster type'], margins = True)
archseries_crosstab_d
Monster type Aqua Beast Beast-Warrior Creator God Cyberse Dinosaur Divine-Beast Dragon Fairy Fiend ... Reptile Rock Sea Serpent Spellcaster Thunder Warrior Winged Beast Wyrm Zombie All
Archseries
"C" 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 9
-Eyes Dragon 0 0 0 0 0 0 0 67 0 0 ... 0 0 0 0 0 0 0 0 3 72
/Assault Mode 0 0 0 0 0 0 0 2 0 0 ... 0 0 0 1 0 1 0 0 1 7
@Ignister 0 0 0 0 18 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 18
A-to-Z 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 16
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
sphinx 0 3 0 0 0 0 0 0 0 0 ... 0 6 0 0 0 0 0 0 0 9
sprout 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 2
tellarknight 0 0 0 0 0 0 0 0 0 1 ... 0 0 0 0 0 15 0 1 0 17
with Eyes of Blue 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 5 0 0 0 0 0 5
All 194 294 185 2 149 81 12 718 445 698 ... 138 214 71 578 95 1241 268 77 158 7263

647 rows × 26 columns

By property¶

archseries_crosstab_e = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Property'], margins = True)
archseries_crosstab_e
Property Continuous Spell Card Continuous Trap Card Counter Trap Card Equip Spell Card Field Spell Card Normal Spell Card Normal Trap Card Quick-Play Spell Card Ritual Spell Card All
Archseries
A.I. 1 3 0 0 1 4 1 2 1 13
Abyss Actor 0 0 0 0 0 1 2 0 0 3
Abyss Script 1 0 0 0 0 5 0 1 0 7
Abyss- 0 1 0 3 0 0 3 0 0 7
Adamancipator 0 0 1 0 1 2 1 0 0 5
... ... ... ... ... ... ... ... ... ... ...
sphinx 0 1 0 0 0 0 0 0 0 1
tellarknight 0 0 0 1 1 0 0 2 0 4
with Chain 0 0 0 0 0 0 4 0 0 4
with Eyes of Blue 1 0 0 0 0 0 0 2 0 3
All 241 287 72 130 181 506 532 255 38 2242

396 rows × 10 columns

Artworks¶

print('Total number of cards with edited or alternate artworks:', formatted_full_df['Artwork'].count())
Total number of cards with edited or alternate artworks: 426
formatted_full_df[['Name','Password','TCG status','OCG status','Artwork']][formatted_full_df['Artwork'].notna()]
Name Password TCG status OCG status Artwork
53 Alluring Mirror Split 92881099 Unlimited Unlimited (Alternate, Edited)
62 Amazoness Spellcaster 81325903 Unlimited Unlimited (Edited,)
71 Ancient Gear Castle 92001300 Unlimited Unlimited (Edited,)
117 Arrivalrivals 29508346 Unlimited Unlimited (Alternate, Edited)
136 Axe of Despair 40619825 Unlimited Unlimited (Edited,)
... ... ... ... ... ...
11940 Soitsu 60246171 Unlimited Unlimited (Edited,)
11991 Stardust Dragon 44508094 Unlimited Unlimited (Alternate,)
11999 Storming Wynn 29013526 Unlimited Unlimited (Alternate, Edited)
12026 Thousand Dragon 41462083 Unlimited Unlimited (Alternate,)
12028 Toon Harpie Lady 64116319 Unlimited Unlimited (Edited,)

426 rows × 5 columns

artwork_value_counts = formatted_full_df['Artwork'].value_counts()
plt.figure(figsize=(20,8))
venn2(subsets = (artwork_value_counts[('Alternate',)], artwork_value_counts[('Edited',)],artwork_value_counts[('Alternate','Edited')]), set_labels = ('Alternate artwork', 'Edited artwork'))
plt.show()

By card type¶

artwork_crosstab = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Card type'])
artwork_crosstab
Card type Monster Card Spell Card Trap Card
Artwork
(Alternate,) 81 4 6
(Alternate, Edited) 78 19 20
(Edited,) 113 62 43

By primary type¶

artwork_crosstab_b = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Primary type'])
artwork_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Normal Monster Ritual Monster Synchro Monster Xyz Monster
Artwork
(Alternate,) 36 12 6 20 0 3 4
(Alternate, Edited) 39 5 7 19 4 0 4
(Edited,) 79 7 1 21 2 2 1

More granularity is unnecessary

Errata¶

print('Total number of cards with name or type errata:', formatted_full_df['Errata'].count())
Total number of cards with name or type errata: 1131
formatted_full_df[['Name','Password','TCG status','OCG status','Errata']][formatted_full_df['Errata'].notna()]
Name Password TCG status OCG status Errata
0 "A" Cell Breeding Device 34541863 Unlimited Unlimited (Name,)
9 7 Completed 86198326 Unlimited Unlimited (Type,)
10 The A. Forces 00403847 Unlimited Unlimited (Type,)
20 Abyss Playhouse - Fantastic Theater 77297908 Unlimited Unlimited (Name,)
45 Advanced Heraldry Art 61314842 Unlimited Unlimited (Name,)
... ... ... ... ... ...
12089 Winged Dragon, Guardian of the Fortress #1 87796900 Unlimited Unlimited (Name,)
12090 Winged Dragon, Guardian of the Fortress #2 57405307 Unlimited Unlimited (Name,)
12092 Winged Sage Falcos 87523462 Unlimited Unlimited (Name,)
12099 Wynn the Wind Charmer 37744402 Unlimited Unlimited (Name,)
12100 Wynn the Wind Charmer, Verdant 30674956 Unlimited Unlimited (Name,)

1131 rows × 5 columns

errata_value_counts = formatted_full_df['Errata'].value_counts()
plt.figure(figsize=(20,8))
venn2(subsets = (errata_value_counts[('Name',)], errata_value_counts[('Type',)],errata_value_counts[('Name','Type')]), set_labels = ('Name Errata', 'Type errata'))
plt.show()

By card type¶

errata_crosstab = pd.crosstab(formatted_full_df['Errata'], formatted_full_df['Card type'])
errata_crosstab
Card type Monster Card Spell Card Trap Card
Errata
(Name,) 311 57 51
(Name, Type) 74 21 2
(Type,) 397 209 9

By primary type¶

errata_crosstab_b = pd.crosstab(formatted_full_df['Errata'], formatted_full_df['Primary type'])
errata_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Normal Monster Ritual Monster Synchro Monster Xyz Monster
Errata
(Name,) 196 46 4 49 3 9 3
(Name, Type) 39 10 0 18 2 5 0
(Type,) 271 22 2 61 2 24 15

More granularity is unnecessary

By artwork¶

errata_crosstab_c = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Errata'])
errata_crosstab_c
Errata (Name,) (Name, Type) (Type,)
Artwork
(Alternate,) 8 15 21
(Alternate, Edited) 8 5 13
(Edited,) 16 8 38

TCG & OCG status¶

TGC status¶

print('Total number of TCG status:', formatted_full_df['TCG status'].nunique())
Total number of TCG status: 7
formatted_full_df.groupby('TCG status', dropna=False).nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata OCG status Modification date
TCG status
Forbidden 99 99 3 7 5 2 6 19 12 27 20 2 4 10 48 54 2 3 4 99
Illegal 38 0 3 3 5 0 6 14 5 11 12 2 2 2 6 7 0 1 1 38
Legal 20 0 1 0 1 0 5 11 5 6 7 0 0 0 0 13 2 1 1 20
Limited 83 83 3 6 6 3 6 16 9 21 21 3 1 1 42 43 3 3 4 83
Not yet released 100 88 3 9 6 3 6 19 11 28 25 5 2 4 39 28 0 0 1 100
Semi-Limited 3 3 2 2 1 0 1 1 1 1 1 0 0 0 3 3 0 1 1 3
Unlimited 11327 11324 3 9 7 6 7 24 14 80 75 13 6 60 343 1118 3 3 4 11230
NaN 448 332 3 9 8 2 7 24 12 55 38 4 4 8 91 107 1 1 5 448
formatted_full_df['TCG status'].value_counts(dropna = False).plot.bar(figsize = (18,6), logy=True, grid = True, rot=45)
plt.show()

By card type¶

# Remove unlimited
tcg_crosstab = pd.crosstab(formatted_full_df['Card type'], formatted_full_df['TCG status']).drop(['Unlimited'], axis=1)
tcg_crosstab
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Card type
Monster Card 64 35 20 43 66 1
Spell Card 25 2 0 35 21 2
Trap Card 10 1 0 5 13 0
plt.figure(figsize = (12,6))
sns.heatmap(tcg_crosstab, annot=True, fmt="g", cmap='viridis', norm=LogNorm())
plt.show()

By monster type¶

# Remove unlimited
tcg_crosstab_b = pd.crosstab(formatted_full_df['Monster type'], formatted_full_df['TCG status']).drop(['Unlimited'], axis=1)
tcg_crosstab_b
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Monster type
Aqua 1 0 2 1 2 0
Beast 0 3 1 2 3 0
Beast-Warrior 2 3 0 2 2 0
Cyberse 2 0 0 1 1 0
Dinosaur 0 0 1 2 2 0
Divine-Beast 0 3 0 0 0 0
Dragon 11 3 1 6 6 0
Fairy 3 4 3 1 5 0
Fiend 5 2 4 3 4 0
Fish 1 0 0 0 6 0
Insect 2 0 0 0 2 0
Machine 6 4 3 6 3 0
Plant 6 1 0 0 2 0
Psychic 2 1 0 1 5 0
Pyro 0 0 0 0 0 0
Reptile 1 0 1 1 0 0
Rock 2 1 1 4 0 0
Sea Serpent 1 0 0 0 1 0
Spellcaster 8 5 1 8 2 0
Thunder 1 1 0 0 1 0
Warrior 4 2 2 2 9 1
Winged Beast 2 2 0 2 8 0
Wyrm 4 0 0 1 0 0
Zombie 0 0 0 0 2 0
plt.figure(figsize = (20,5))
sns.heatmap(tcg_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square = True, norm=LogNorm())
plt.show()

By archseries¶

# Remove unlimited
tcg_crosstab_c = pd.crosstab(exploded_archseries['Archseries'].where(exploded_archseries['OCG status']!='Unlimited'), exploded_archseries['TCG status'], margins = True)
tcg_crosstab_c
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited Unlimited All
Archseries
-Eyes Dragon 1 0 0 0 0 0 0 1
A-to-Z 0 0 0 0 0 0 1 1
Adventurer Token (series) 0 0 0 0 0 0 3 3
Amazoness 0 0 0 0 0 0 1 1
Ancient Gear 0 0 1 0 0 0 0 1
... ... ... ... ... ... ... ... ...
Zexal 1 0 0 0 0 0 0 1
Zoodiac 3 0 0 1 0 0 0 4
roid 0 0 0 1 0 0 0 1
tellarknight 1 0 0 0 0 0 0 1
All 63 40 16 31 7 4 59 220

122 rows × 8 columns

OCG status¶

print('Total number of OCG status:', formatted_full_df['OCG status'].nunique())
Total number of OCG status: 7
formatted_full_df.groupby('OCG status', dropna=False).nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status Modification date
OCG status
Forbidden 89 89 3 6 5 3 6 19 11 27 22 3 4 8 40 45 2 3 3 89
Illegal 32 1 3 2 6 1 6 12 8 14 15 2 2 2 8 8 0 1 1 32
Legal 39 0 1 0 2 0 6 17 7 8 8 0 0 0 0 24 2 1 1 39
Limited 71 71 3 6 6 3 6 15 9 18 20 3 3 5 38 39 2 3 3 71
Not yet released 68 0 3 6 6 1 6 16 11 21 18 3 2 2 35 32 0 0 0 68
Semi-Limited 20 20 3 4 2 0 4 5 4 7 6 1 0 0 15 13 0 1 4 20
Unlimited 11757 11732 3 9 7 6 7 25 14 81 76 13 6 59 350 1141 3 3 4 11665
NaN 38 14 3 6 6 1 5 14 5 12 13 0 1 1 15 5 0 0 3 38
formatted_full_df['OCG status'].value_counts(dropna = False).plot.bar(figsize = (18,6), logy=True, grid = True, rot=45)
plt.show()

By card type¶

# Remove unlimited
ocg_crosstab = pd.crosstab(formatted_full_df['Card type'], formatted_full_df['OCG status']).drop(['Unlimited'], axis=1)
ocg_crosstab
OCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Card type
Monster Card 57 30 39 39 43 8
Spell Card 22 1 0 29 19 11
Trap Card 10 1 0 3 6 1
plt.figure(figsize = (12,6))
sns.heatmap(ocg_crosstab, annot=True, fmt="g", cmap='viridis', norm=LogNorm())
plt.show()

By monster type¶

# Remove unlimited
ocg_crosstab_b = pd.crosstab(formatted_full_df['Monster type'], formatted_full_df['OCG status']).drop(['Unlimited'], axis=1)
ocg_crosstab_b
OCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Monster type
Aqua 2 0 2 1 1 1
Beast 1 2 4 0 1 0
Beast-Warrior 3 2 0 1 0 1
Creator God 0 0 0 0 0 0
Cyberse 2 0 2 1 0 0
Dinosaur 0 0 1 1 0 0
Divine-Beast 0 3 0 0 0 0
Dragon 10 3 1 4 3 0
Fairy 2 3 4 4 4 0
Fiend 5 1 7 1 7 0
Fish 1 0 0 0 1 0
Insect 1 0 0 0 7 0
Machine 5 3 6 7 4 1
Plant 5 0 1 1 1 0
Psychic 1 1 0 3 3 0
Pyro 0 0 1 1 0 0
Reptile 1 0 1 0 0 0
Rock 1 1 1 2 1 0
Sea Serpent 1 0 0 0 0 0
Spellcaster 7 7 1 8 4 3
Thunder 0 0 1 3 1 0
Warrior 4 3 3 1 2 2
Winged Beast 3 1 1 0 1 0
Wyrm 2 0 0 0 2 0
Zombie 0 0 2 0 0 0
plt.figure(figsize = (20,5))
sns.heatmap(ocg_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square = True, norm=LogNorm())
plt.show()

By archseries¶

# Remove unlimited
ocg_crosstab_c = pd.crosstab(exploded_archseries['Archseries'].where(exploded_archseries['OCG status']!='Unlimited'), exploded_archseries['OCG status'], margins = True)
ocg_crosstab_c

TCG vs. OCG status¶

cg_crosstab = pd.crosstab(formatted_full_df['OCG status'],formatted_full_df['TCG status'], dropna=False, margins = False)
cg_crosstab
plt.figure(figsize = (10,8))
sns.heatmap(cg_crosstab, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

HTML export¶

! jupyter nbconvert Cards.ipynb --to=HTML --TemplateExporter.exclude_input_prompt=True --TemplateExporter.exclude_output_prompt=True

Searches¶

formatted_full_df.loc[formatted_full_df['OCG status'] == 'Not yet released'].loc[formatted_full_df['TCG status'] == 'Not yet released']

Git¶

! git add .
! git commit -m {"Update-" + pd.Timestamp.now().strftime("%d%m%Y")}
! git push